home *** CD-ROM | disk | FTP | other *** search
/ The Utilities Experience / The Utilities Experience - Volume 1.iso / software / misc / o-z / x-windows / gs262 / gscolor.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-29  |  11.1 KB  |  398 lines

  1. /* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* gscolor.c */
  20. /* Color and halftone operators for Ghostscript library */
  21. #include "gx.h"
  22. #include "gserrors.h"
  23. #include "gscspace.h"
  24. #include "gxcolor.h"
  25. #include "gxdevice.h"            /* for gx_color_index */
  26. #include "gxrefct.h"
  27. #include "gzstate.h"
  28. #include "gzcolor.h"
  29.  
  30. #ifdef AMIGA
  31. extern int gx_remap_color(gs_state *);
  32. #endif
  33.  
  34. /* Define the standard color space types. */
  35. extern cs_proc_remap_color(gx_remap_DeviceGray);
  36. extern cs_proc_remap_color(gx_remap_DeviceRGB);
  37. extern cs_proc_remap_color(gx_remap_DeviceCMYK);
  38. const gs_color_space_type
  39.     gs_color_space_type_DeviceGray =
  40.      { gs_color_space_index_DeviceGray, 1,
  41.        gx_remap_DeviceGray, gx_no_install_cspace, gx_no_adjust_count
  42.      },
  43.     gs_color_space_type_DeviceRGB =
  44.      { gs_color_space_index_DeviceRGB, 3,
  45.        gx_remap_DeviceRGB, gx_no_install_cspace, gx_no_adjust_count
  46.      },
  47.     gs_color_space_type_DeviceCMYK =
  48.      { gs_color_space_index_DeviceCMYK, 4,
  49.        gx_remap_DeviceCMYK, gx_no_install_cspace, gx_no_adjust_count
  50.      };
  51.  
  52. /* Null color space installation procedure. */
  53. int
  54. gx_no_install_cspace(gs_color_space *pcs, gs_state *pgs)
  55. {    return 0;
  56. }
  57.  
  58. /* Null reference count adjustment procedure. */
  59. int
  60. gx_no_adjust_count(gs_color_space *pcs, gs_state *pgs, int delta)
  61. {    return 0;
  62. }
  63.  
  64. /* Force a parameter into the range [0.0..1.0]. */
  65. #define force_unit(p) (p < 0.0 ? 0.0 : p > 1.0 ? 1.0 : p)
  66. frac gx_color_unit_param(P1(floatp));
  67.  
  68. /* Forward declarations */
  69. private void load_transfer_map(P2(gs_state *, gx_transfer_map *));
  70.  
  71. /* setgray */
  72. int
  73. gs_setgray(gs_state *pgs, floatp gray)
  74. {    int code;
  75.     if ( pgs->in_cachedevice ) return_error(gs_error_undefined);
  76.     code = cs_adjust_count(pgs, -1);
  77.     if ( code < 0 ) return code;
  78.     pgs->ccolor->paint.values[0] = gray;
  79.     pgs->color_space->type = &gs_color_space_type_DeviceGray;
  80.     return gx_remap_color(pgs);
  81. }
  82.  
  83. /* currentgray */
  84. float
  85. gs_currentgray(const gs_state *pgs)
  86. {    gs_client_color *pcc = pgs->ccolor;
  87.     switch ( pgs->color_space->type->index )
  88.     {
  89.     case gs_color_space_index_DeviceGray:
  90.         return pcc->paint.values[0];
  91.     case gs_color_space_index_DeviceRGB:
  92. #ifndef AMIGA
  93.         return frac2float(color_rgb_to_gray(
  94.             float2frac(pcc->paint.values[0]),
  95.             float2frac(pcc->paint.values[1]),
  96.             float2frac(pcc->paint.values[2]),
  97.             pgs));
  98. #else
  99.         return (float)(frac2float(color_rgb_to_gray(
  100.             float2frac(pcc->paint.values[0]),
  101.             float2frac(pcc->paint.values[1]),
  102.             float2frac(pcc->paint.values[2]),
  103.             pgs)));
  104. #endif
  105.     case gs_color_space_index_DeviceCMYK:
  106. #ifndef AMIGA
  107.         return frac2float(color_cmyk_to_gray(
  108.             float2frac(pcc->paint.values[0]),
  109.             float2frac(pcc->paint.values[1]),
  110.             float2frac(pcc->paint.values[2]),
  111.             float2frac(pcc->paint.values[3]),
  112.             pgs));
  113. #else
  114.         return (float)(frac2float(color_cmyk_to_gray(
  115.             float2frac(pcc->paint.values[0]),
  116.             float2frac(pcc->paint.values[1]),
  117.             float2frac(pcc->paint.values[2]),
  118.             float2frac(pcc->paint.values[3]),
  119.             pgs)));
  120. #endif
  121.     default:
  122.         return 0.0;
  123.     }
  124. }
  125.  
  126. /* sethsbcolor */
  127. int
  128. gs_sethsbcolor(gs_state *pgs, floatp h, floatp s, floatp b)
  129. {    float rgb[3];
  130.     color_hsb_to_rgb(force_unit(h), force_unit(s), force_unit(b), rgb);
  131.     return gs_setrgbcolor(pgs, rgb[0], rgb[1], rgb[2]);
  132. }
  133.  
  134. /* currenthsbcolor */
  135. int
  136. gs_currenthsbcolor(const gs_state *pgs, float pr3[3])
  137. {    float rgb[3];
  138.     gs_currentrgbcolor(pgs, rgb);
  139.     color_rgb_to_hsb(rgb[0], rgb[1], rgb[2], pr3);
  140.     return 0;
  141. }
  142.  
  143. /* setrgbcolor */
  144. int
  145. gs_setrgbcolor(gs_state *pgs, floatp r, floatp g, floatp b)
  146. {    int code;
  147.     gs_client_color *pcc = pgs->ccolor;
  148.     if ( pgs->in_cachedevice ) return_error(gs_error_undefined);
  149.     code = cs_adjust_count(pgs, -1);
  150.     if ( code < 0 ) return code;
  151.     pcc->paint.values[0] = r;
  152.     pcc->paint.values[1] = g;
  153.     pcc->paint.values[2] = b;
  154.     pgs->color_space->type = &gs_color_space_type_DeviceRGB;
  155.     return gx_remap_color(pgs);
  156. }
  157.  
  158. /* currentrgbcolor */
  159. int
  160. gs_currentrgbcolor(const gs_state *pgs, float pr3[3])
  161. {    gs_client_color *pcc = pgs->ccolor;
  162.     switch ( pgs->color_space->type->index )
  163.     {
  164.     case gs_color_space_index_DeviceGray:
  165.         pr3[0] = pr3[1] = pr3[2] = pcc->paint.values[0];
  166.         break;
  167.     case gs_color_space_index_DeviceRGB:
  168.         pr3[0] = pcc->paint.values[0];
  169.         pr3[1] = pcc->paint.values[1];
  170.         pr3[2] = pcc->paint.values[2];
  171.         break;
  172.     case gs_color_space_index_DeviceCMYK:
  173.     {    frac frgb[3];
  174.         color_cmyk_to_rgb(
  175.             float2frac(pcc->paint.values[0]),
  176.             float2frac(pcc->paint.values[1]),
  177.             float2frac(pcc->paint.values[2]),
  178.             float2frac(pcc->paint.values[3]),
  179.             pgs, frgb);
  180.         pr3[0] = frac2float(frgb[0]);
  181.         pr3[1] = frac2float(frgb[1]);
  182.         pr3[2] = frac2float(frgb[2]);
  183.     }    break;
  184.     default:
  185.         pr3[0] = pr3[1] = pr3[2] = 0.0;
  186.     }
  187.     return 0;
  188. }
  189.  
  190. /* setcmykcolor */
  191. int
  192. gs_setcmykcolor(gs_state *pgs, floatp c, floatp m, floatp y, floatp k)
  193. {    int code;
  194.     gs_client_color *pcc = pgs->ccolor;
  195.     if ( pgs->in_cachedevice ) return_error(gs_error_undefined);
  196.     code = cs_adjust_count(pgs, -1);
  197.     if ( code < 0 ) return code;
  198.     pcc->paint.values[0] = c;
  199.     pcc->paint.values[1] = m;
  200.     pcc->paint.values[2] = y;
  201.     pcc->paint.values[3] = k;
  202.     pgs->color_space->type = &gs_color_space_type_DeviceCMYK;
  203.     return gx_remap_color(pgs);
  204. }
  205.  
  206. /* currentcmykcolor */
  207. int
  208. gs_currentcmykcolor(const gs_state *pgs, float pr4[4])
  209. {    gs_client_color *pcc = pgs->ccolor;
  210.     switch ( pgs->color_space->type->index )
  211.     {
  212.     case gs_color_space_index_DeviceGray:
  213.         pr4[0] = pr4[1] = pr4[2] = 0.0;
  214.         pr4[3] = 1.0 - pcc->paint.values[0];
  215.         break;
  216.     case gs_color_space_index_DeviceRGB:
  217.     {    frac fcmyk[4];
  218.         color_rgb_to_cmyk(
  219.             float2frac(pcc->paint.values[0]),
  220.             float2frac(pcc->paint.values[1]),
  221.             float2frac(pcc->paint.values[2]),
  222.             pgs, fcmyk);
  223.         pr4[0] = frac2float(fcmyk[0]);
  224.         pr4[1] = frac2float(fcmyk[1]);
  225.         pr4[2] = frac2float(fcmyk[2]);
  226.         pr4[3] = frac2float(fcmyk[3]);
  227.     }    break;
  228.     case gs_color_space_index_DeviceCMYK:
  229.         pr4[0] = pcc->paint.values[0];
  230.         pr4[1] = pcc->paint.values[1];
  231.         pr4[2] = pcc->paint.values[2];
  232.         pr4[3] = pcc->paint.values[3];
  233.         break;
  234.     default:
  235.         pr4[0] = pr4[1] = pr4[2] = 0.0;
  236.         pr4[3] = 1.0;
  237.     }
  238.     return 0;
  239. }
  240.  
  241. /* setblackgeneration */
  242. int
  243. gs_setblackgeneration(gs_state *pgs, gs_mapping_proc proc)
  244. {    /****** INCOMPLETE ******/
  245.     pgs->black_generation = proc;
  246.     return 0;
  247. }
  248.  
  249. /* currentblackgeneration */
  250. gs_mapping_proc
  251. gs_currentblackgeneration(const gs_state *pgs)
  252. {    return pgs->black_generation;
  253. }
  254.  
  255. /* setundercolorremoval */
  256. int
  257. gs_setundercolorremoval(gs_state *pgs, gs_mapping_proc proc)
  258. {    /****** INCOMPLETE ******/
  259.     pgs->undercolor_removal = proc;
  260.     return 0;
  261. }
  262.  
  263. /* currentundercolorremoval */
  264. gs_mapping_proc
  265. gs_currentundercolorremoval(const gs_state *pgs)
  266. {    return pgs->undercolor_removal;
  267. }
  268.  
  269. /* settransfer */
  270. /* Remap=0 is used by the interpreter. */
  271. int
  272. gs_settransfer_remap(gs_state *pgs, gs_mapping_proc tproc, int remap)
  273. {    gx_transfer *ptran = &pgs->transfer;
  274.     /* We can safely decrement the reference counts */
  275.     /* of the non-gray transfer maps, because */
  276.     /* if any of them get freed, the rc_unshare can't fail. */
  277.     rc_decrement(ptran->red, pgs->memory_procs, "gs_settransfer");
  278.     rc_decrement(ptran->green, pgs->memory_procs, "gs_settransfer");
  279.     rc_decrement(ptran->blue, pgs->memory_procs, "gs_settransfer");
  280.     rc_unshare(ptran->gray, gx_transfer_map, pgs->memory_procs,
  281.            goto fail, "gs_settransfer");
  282.     ptran->gray->proc = tproc;
  283.     ptran->red = ptran->gray;
  284.     ptran->green = ptran->gray;
  285.     ptran->blue = ptran->gray;
  286.     ptran->gray->rc.ref_count += 3;
  287.     if ( remap )
  288.     {    load_transfer_map(pgs, ptran->gray);
  289.         return gx_remap_color(pgs);
  290.     }
  291.     else
  292.         return 0;
  293. fail:    rc_increment(ptran->red);
  294.     rc_increment(ptran->green);
  295.     rc_increment(ptran->blue);
  296.     return gs_error_VMerror;
  297. }
  298. int
  299. gs_settransfer(gs_state *pgs, gs_mapping_proc tproc)
  300. {    return gs_settransfer_remap(pgs, tproc, 1);
  301. }
  302.  
  303. /* currenttransfer */
  304. gs_mapping_proc
  305. gs_currenttransfer(const gs_state *pgs)
  306. {    return pgs->transfer.gray->proc;
  307. }
  308.  
  309. /* setcolortransfer */
  310. /* Remap=0 is used by the interpreter. */
  311. int
  312. gs_setcolortransfer_remap(gs_state *pgs, gs_mapping_proc red_proc,
  313.   gs_mapping_proc green_proc, gs_mapping_proc blue_proc,
  314.   gs_mapping_proc gray_proc, int remap)
  315. {    gx_transfer *ptran = &pgs->transfer;
  316.     gx_transfer old;
  317.     old = *ptran;
  318.     rc_unshare(ptran->gray, gx_transfer_map, pgs->memory_procs,
  319.            goto fgray, "gs_setcolortransfer");
  320.     rc_unshare(ptran->red, gx_transfer_map, pgs->memory_procs,
  321.            goto fred, "gs_setcolortransfer");
  322.     rc_unshare(ptran->green, gx_transfer_map, pgs->memory_procs,
  323.            goto fgreen, "gs_setcolortransfer");
  324.     rc_unshare(ptran->blue, gx_transfer_map, pgs->memory_procs,
  325.            goto fblue, "gs_setcolortransfer");
  326.     ptran->red->proc = red_proc;
  327.     ptran->green->proc = green_proc;
  328.     ptran->blue->proc = blue_proc;
  329.     ptran->gray->proc = gray_proc;
  330.     if ( remap )
  331.     {    load_transfer_map(pgs, ptran->red);
  332.         load_transfer_map(pgs, ptran->green);
  333.         load_transfer_map(pgs, ptran->blue);
  334.         load_transfer_map(pgs, ptran->gray);
  335.         return gx_remap_color(pgs);
  336.     }
  337.     else
  338.         return 0;
  339. fblue:    rc_assign(ptran->green, old.green, pgs->memory_procs, "setcolortransfer");
  340. fgreen:    rc_assign(ptran->red, old.red, pgs->memory_procs, "setcolortransfer");
  341. fred:    rc_assign(ptran->gray, old.gray, pgs->memory_procs, "setcolortransfer");
  342. fgray:    return gs_error_VMerror;
  343. }
  344. int
  345. gs_setcolortransfer(gs_state *pgs, gs_mapping_proc red_proc,
  346.   gs_mapping_proc green_proc, gs_mapping_proc blue_proc,
  347.   gs_mapping_proc gray_proc)
  348. {    return gs_setcolortransfer_remap(pgs, red_proc, green_proc,
  349.                      blue_proc, gray_proc, 1);
  350. }
  351.  
  352. /* currentcolortransfer */
  353. void
  354. gs_currentcolortransfer(const gs_state *pgs, gs_mapping_proc procs[4])
  355. {    const gx_transfer *ptran = &pgs->transfer;
  356.     procs[0] = ptran->red->proc;
  357.     procs[1] = ptran->green->proc;
  358.     procs[2] = ptran->blue->proc;
  359.     procs[3] = ptran->gray->proc;
  360. }
  361.  
  362. /* ------ Non-operator routines ------ */
  363.  
  364. /* Set up black for writing into the character cache. */
  365. void
  366. gx_set_black(gs_state *pgs)
  367. {    gx_device_color *pdc = pgs->dev_color;
  368.     gs_client_color *pc = pgs->ccolor;
  369.     pc->paint.values[0] = 0.0;
  370.     pgs->color_space->type = &gs_color_space_type_DeviceGray;
  371.     pdc->color1 = pdc->color2 = 1;
  372.     pdc->halftone_level = 0;
  373. }
  374.  
  375. /* Force a parameter into the range [0..1], */
  376. /* and convert to a frac. */
  377. frac
  378. gx_color_unit_param(floatp fval)
  379. {    if ( fval <= 0.0 )
  380.         return frac_0;
  381.     else if ( fval >= 1.0 )
  382.         return frac_1;
  383.     else
  384.         return float2frac(fval);
  385. }
  386.  
  387. /* ------ Internal routines ------ */
  388.  
  389. /* Load one cached transfer map. */
  390. private void
  391. load_transfer_map(gs_state *pgs, gx_transfer_map *pmap)
  392. {    gs_mapping_proc proc = pmap->proc;
  393.     frac *values = pmap->values;
  394.     int i;
  395.     for ( i = 0; i < transfer_map_size; i++ )
  396.       values[i] = gx_color_unit_param((*proc)(pgs, (float)i / (transfer_map_size - 1)));
  397. }
  398.